<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="generator" content="VuePress 2.0.0-beta.25">
    <link rel="icon" href="/eurynome-cloud/images/logo.png"><meta name="keywords" content="Eurynome Cloud,微服务,Spring Boot,Spirng Cloud,Spring Cloud Alibaba,Spring Security,OAuth2,Nacos,Skywalking"><title>Spring Data JPA | Eurynome Cloud</title><meta name="description" content="Eurynome Cloud, 在线文档, 微服务, 微服务架构, Spring Boot，Spring Cloud，Spring Cloud Alibaba, Spring Security, OAuth 2, Skywalking, Nacos">
    <link rel="preload" href="/eurynome-cloud/assets/js/runtime~app.70302f05.js" as="script"><link rel="preload" href="/eurynome-cloud/assets/css/styles.03bfbc71.css" as="style"><link rel="preload" href="/eurynome-cloud/assets/js/567.94e28fdc.js" as="script"><link rel="preload" href="/eurynome-cloud/assets/js/app.a36212f7.js" as="script">
    <link rel="stylesheet" href="/eurynome-cloud/assets/css/styles.03bfbc71.css">
  </head>
  <body>
    <div id="app"><!--[--><div class="theme-container"><header class="navbar"><div class="toggle-sidebar-button" title="toggle sidebar" aria-expanded="false" role="button" tabindex="0"><div class="icon" aria-hidden="true"><span></span><span></span><span></span></div></div><span><a href="/eurynome-cloud/" class=""><img class="logo" src="/eurynome-cloud/images/logo.png" alt="Eurynome Cloud"><span class="site-name can-hide">Eurynome Cloud</span></a></span><div class="navbar-links-wrapper" style=""><!--[--><!--]--><nav class="navbar-links can-hide"><!--[--><div class="navbar-links-item"><a href="/eurynome-cloud/documents/" class="nav-link" aria-label="指南"><!--[--><!--]--> 指南 <!--[--><!--]--></a></div><div class="navbar-links-item"><a href="/eurynome-cloud/documents-athena/" class="nav-link" aria-label="单体版"><!--[--><!--]--> 单体版 <!--[--><!--]--></a></div><div class="navbar-links-item"><a href="/eurynome-cloud/microservices/" class="nav-link" aria-label="微服务技术栈"><!--[--><!--]--> 微服务技术栈 <!--[--><!--]--></a></div><div class="navbar-links-item"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="了解更多"><span class="title">了解更多</span><span class="arrow down"></span></button><button class="mobile-dropdown-title" type="button" aria-label="了解更多"><span class="title">了解更多</span><span class="right arrow"></span></button><!--[--><ul style="display:none;" class="nav-dropdown"><!--[--><li class="dropdown-item"><!--[--><h4 class="dropdown-subtitle"><span>延伸</span></h4><ul class="dropdown-subitem-wrapper"><!--[--><li class="dropdown-subitem"><a href="/eurynome-cloud/basic-knowledge/" class="nav-link router-link-active" aria-label="了解基础知识"><!--[--><!--]--> 了解基础知识 <!--[--><!--]--></a></li><!--]--></ul><!--]--></li><li class="dropdown-item"><!--[--><h4 class="dropdown-subtitle"><span>帮助</span></h4><ul class="dropdown-subitem-wrapper"><!--[--><li class="dropdown-subitem"><a class="nav-link external" href="https://gitee.com/herodotus/eurynome-cloud/issues" rel="noopener noreferrer" target="_blank" aria-label="我要提问"><!--[--><!--]--> 我要提问 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-subitem"><a href="/eurynome-cloud/others/README.md" class="nav-link" aria-label="常见问题"><!--[--><!--]--> 常见问题 <!--[--><!--]--></a></li><li class="dropdown-subitem"><a href="/eurynome-cloud/others/更新日志.md" class="nav-link" aria-label="更新日志"><!--[--><!--]--> 更新日志 <!--[--><!--]--></a></li><li class="dropdown-subitem"><a class="nav-link external" href="https://jq.qq.com/?_wv=1027&amp;k=bIerJVy8" rel="noopener noreferrer" target="_blank" aria-label="加入QQ群"><!--[--><!--]--> 加入QQ群 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><!--]--></ul><!--]--></li><!--]--></ul><!--]--></div></div><div class="navbar-links-item"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="Gitee"><span class="title">Gitee</span><span class="arrow down"></span></button><button class="mobile-dropdown-title" type="button" aria-label="Gitee"><span class="title">Gitee</span><span class="right arrow"></span></button><!--[--><ul style="display:none;" class="nav-dropdown"><!--[--><li class="dropdown-item"><a class="nav-link external" href="https://gitee.com/herodotus/eurynome-cloud" rel="noopener noreferrer" target="_blank" aria-label="后端源码"><!--[--><!--]--> 后端源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-item"><a class="nav-link external" href="https://gitee.com/herodotus/eurynome-cloud-ui" rel="noopener noreferrer" target="_blank" aria-label="前端源码"><!--[--><!--]--> 前端源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-item"><a class="nav-link external" href="https://gitee.com/herodotus/herodotus-cloud-athena" rel="noopener noreferrer" target="_blank" aria-label="单体版源码"><!--[--><!--]--> 单体版源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><!--]--></ul><!--]--></div></div><div class="navbar-links-item"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="Github"><span class="title">Github</span><span class="arrow down"></span></button><button class="mobile-dropdown-title" type="button" aria-label="Github"><span class="title">Github</span><span class="right arrow"></span></button><!--[--><ul style="display:none;" class="nav-dropdown"><!--[--><li class="dropdown-item"><a class="nav-link external" href="https://github.com/herodotus-cloud/eurynome-cloud" rel="noopener noreferrer" target="_blank" aria-label="后端源码"><!--[--><!--]--> 后端源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-item"><a class="nav-link external" href="https://github.com/herodotus-cloud/eurynome-cloud-ui" rel="noopener noreferrer" target="_blank" aria-label="前端源码"><!--[--><!--]--> 前端源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-item"><a class="nav-link external" href="https://github.com/herodotus-cloud/herodotus-cloud-athena" rel="noopener noreferrer" target="_blank" aria-label="单体版源码"><!--[--><!--]--> 单体版源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><!--]--></ul><!--]--></div></div><!--]--></nav><!--[--><!--]--><button class="toggle-dark-button" title="toggle dark mode"><svg style="" class="icon" focusable="false" viewBox="0 0 32 32"><path d="M16 12.005a4 4 0 1 1-4 4a4.005 4.005 0 0 1 4-4m0-2a6 6 0 1 0 6 6a6 6 0 0 0-6-6z" fill="currentColor"></path><path d="M5.394 6.813l1.414-1.415l3.506 3.506L8.9 10.318z" fill="currentColor"></path><path d="M2 15.005h5v2H2z" fill="currentColor"></path><path d="M5.394 25.197L8.9 21.691l1.414 1.415l-3.506 3.505z" fill="currentColor"></path><path d="M15 25.005h2v5h-2z" fill="currentColor"></path><path d="M21.687 23.106l1.414-1.415l3.506 3.506l-1.414 1.414z" fill="currentColor"></path><path d="M25 15.005h5v2h-5z" fill="currentColor"></path><path d="M21.687 8.904l3.506-3.506l1.414 1.415l-3.506 3.505z" fill="currentColor"></path><path d="M15 2.005h2v5h-2z" fill="currentColor"></path></svg><svg style="display:none;" class="icon" focusable="false" viewBox="0 0 32 32"><path d="M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z" fill="currentColor"></path></svg></button><form class="search-box" role="search"><input type="search" placeholder="搜索" autocomplete="off" spellcheck="false" value><!----></form></div></header><div class="sidebar-mask"></div><aside class="sidebar"><nav class="navbar-links"><!--[--><div class="navbar-links-item"><a href="/eurynome-cloud/documents/" class="nav-link" aria-label="指南"><!--[--><!--]--> 指南 <!--[--><!--]--></a></div><div class="navbar-links-item"><a href="/eurynome-cloud/documents-athena/" class="nav-link" aria-label="单体版"><!--[--><!--]--> 单体版 <!--[--><!--]--></a></div><div class="navbar-links-item"><a href="/eurynome-cloud/microservices/" class="nav-link" aria-label="微服务技术栈"><!--[--><!--]--> 微服务技术栈 <!--[--><!--]--></a></div><div class="navbar-links-item"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="了解更多"><span class="title">了解更多</span><span class="arrow down"></span></button><button class="mobile-dropdown-title" type="button" aria-label="了解更多"><span class="title">了解更多</span><span class="right arrow"></span></button><!--[--><ul style="display:none;" class="nav-dropdown"><!--[--><li class="dropdown-item"><!--[--><h4 class="dropdown-subtitle"><span>延伸</span></h4><ul class="dropdown-subitem-wrapper"><!--[--><li class="dropdown-subitem"><a href="/eurynome-cloud/basic-knowledge/" class="nav-link router-link-active" aria-label="了解基础知识"><!--[--><!--]--> 了解基础知识 <!--[--><!--]--></a></li><!--]--></ul><!--]--></li><li class="dropdown-item"><!--[--><h4 class="dropdown-subtitle"><span>帮助</span></h4><ul class="dropdown-subitem-wrapper"><!--[--><li class="dropdown-subitem"><a class="nav-link external" href="https://gitee.com/herodotus/eurynome-cloud/issues" rel="noopener noreferrer" target="_blank" aria-label="我要提问"><!--[--><!--]--> 我要提问 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-subitem"><a href="/eurynome-cloud/others/README.md" class="nav-link" aria-label="常见问题"><!--[--><!--]--> 常见问题 <!--[--><!--]--></a></li><li class="dropdown-subitem"><a href="/eurynome-cloud/others/更新日志.md" class="nav-link" aria-label="更新日志"><!--[--><!--]--> 更新日志 <!--[--><!--]--></a></li><li class="dropdown-subitem"><a class="nav-link external" href="https://jq.qq.com/?_wv=1027&amp;k=bIerJVy8" rel="noopener noreferrer" target="_blank" aria-label="加入QQ群"><!--[--><!--]--> 加入QQ群 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><!--]--></ul><!--]--></li><!--]--></ul><!--]--></div></div><div class="navbar-links-item"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="Gitee"><span class="title">Gitee</span><span class="arrow down"></span></button><button class="mobile-dropdown-title" type="button" aria-label="Gitee"><span class="title">Gitee</span><span class="right arrow"></span></button><!--[--><ul style="display:none;" class="nav-dropdown"><!--[--><li class="dropdown-item"><a class="nav-link external" href="https://gitee.com/herodotus/eurynome-cloud" rel="noopener noreferrer" target="_blank" aria-label="后端源码"><!--[--><!--]--> 后端源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-item"><a class="nav-link external" href="https://gitee.com/herodotus/eurynome-cloud-ui" rel="noopener noreferrer" target="_blank" aria-label="前端源码"><!--[--><!--]--> 前端源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-item"><a class="nav-link external" href="https://gitee.com/herodotus/herodotus-cloud-athena" rel="noopener noreferrer" target="_blank" aria-label="单体版源码"><!--[--><!--]--> 单体版源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><!--]--></ul><!--]--></div></div><div class="navbar-links-item"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="Github"><span class="title">Github</span><span class="arrow down"></span></button><button class="mobile-dropdown-title" type="button" aria-label="Github"><span class="title">Github</span><span class="right arrow"></span></button><!--[--><ul style="display:none;" class="nav-dropdown"><!--[--><li class="dropdown-item"><a class="nav-link external" href="https://github.com/herodotus-cloud/eurynome-cloud" rel="noopener noreferrer" target="_blank" aria-label="后端源码"><!--[--><!--]--> 后端源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-item"><a class="nav-link external" href="https://github.com/herodotus-cloud/eurynome-cloud-ui" rel="noopener noreferrer" target="_blank" aria-label="前端源码"><!--[--><!--]--> 前端源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><li class="dropdown-item"><a class="nav-link external" href="https://github.com/herodotus-cloud/herodotus-cloud-athena" rel="noopener noreferrer" target="_blank" aria-label="单体版源码"><!--[--><!--]--> 单体版源码 <span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span><!--[--><!--]--></a></li><!--]--></ul><!--]--></div></div><!--]--></nav><!--[--><!--]--><ul class="sidebar-links"><!--[--><!--[--><p class="sidebar-heading sidebar-item active">基础知识</p><ul class=""><li><!--[--><a href="/eurynome-cloud/basic-knowledge/" class="nav-link router-link-active sidebar-item" aria-label="介绍"><!--[--><!--]--> 介绍 <!--[--><!--]--></a><!----><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html" class="router-link-active router-link-exact-active nav-link router-link-active sidebar-item active" aria-label="Spring Data JPA"><!--[--><!--]--> Spring Data JPA <!--[--><!--]--></a><ul class="sidebar-sub-items"><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#jpa" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="JPA"><!--[--><!--]--> JPA <!--[--><!--]--></a><ul class="sidebar-sub-items"><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#spring-data-jpa-1" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="Spring Data Jpa"><!--[--><!--]--> Spring Data Jpa <!--[--><!--]--></a><!----><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#jpa、hibernate、spring-data-jpa三者之间的关系" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="Jpa、Hibernate、Spring Data Jpa三者之间的关系"><!--[--><!--]--> Jpa、Hibernate、Spring Data Jpa三者之间的关系 <!--[--><!--]--></a><!----><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#spring-data-jpa的java配置方案" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="Spring Data Jpa的java配置方案"><!--[--><!--]--> Spring Data Jpa的java配置方案 <!--[--><!--]--></a><!----><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#spring-boot整合spring-data-jpa" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="Spring Boot整合Spring Data Jpa"><!--[--><!--]--> Spring Boot整合Spring Data Jpa <!--[--><!--]--></a><!----><!--]--></li></ul><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#spring-data-jpa的使用" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="Spring Data Jpa的使用"><!--[--><!--]--> Spring Data Jpa的使用 <!--[--><!--]--></a><ul class="sidebar-sub-items"><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#spring-data-jpa-uml类图" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="Spring Data Jpa UML类图"><!--[--><!--]--> Spring Data Jpa UML类图 <!--[--><!--]--></a><!----><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#简单的rest-crud示例" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="简单的REST CRUD示例"><!--[--><!--]--> 简单的REST CRUD示例 <!--[--><!--]--></a><!----><!--]--></li></ul><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#spring-data-jpa使用详解" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="Spring Data Jpa使用详解"><!--[--><!--]--> Spring Data Jpa使用详解 <!--[--><!--]--></a><ul class="sidebar-sub-items"><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#spring-data查询方法" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="Spring Data查询方法"><!--[--><!--]--> Spring Data查询方法 <!--[--><!--]--></a><!----><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#查询方法" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="查询方法"><!--[--><!--]--> 查询方法 <!--[--><!--]--></a><!----><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#多表查询" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="多表查询"><!--[--><!--]--> 多表查询 <!--[--><!--]--></a><!----><!--]--></li></ul><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#审计auditing" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="审计Auditing"><!--[--><!--]--> 审计Auditing <!--[--><!--]--></a><ul class="sidebar-sub-items"><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#实现auditoraware接口" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="实现AuditorAware接口"><!--[--><!--]--> 实现AuditorAware接口 <!--[--><!--]--></a><!----><!--]--></li><li><!--[--><a aria-current="page" href="/eurynome-cloud/basic-knowledge/spring-data-jpa.html#启用jpa审计功能" class="router-link-active router-link-exact-active nav-link sidebar-item" aria-label="启用Jpa审计功能"><!--[--><!--]--> 启用Jpa审计功能 <!--[--><!--]--></a><!----><!--]--></li></ul><!--]--></li></ul><!--]--></li></ul><!--]--><!--]--></ul><!--[--><!--]--></aside><!--[--><main class="page"><!--[--><!--]--><div class="theme-default-content"><!--[--><h1 id="spring-data-jpa" tabindex="-1"><a class="header-anchor" href="#spring-data-jpa" aria-hidden="true">#</a> Spring Data JPA</h1><h2 id="jpa" tabindex="-1"><a class="header-anchor" href="#jpa" aria-hidden="true">#</a> JPA</h2><p><code>JPA</code>(<code>Java Persistence API</code>)意即Java持久化API，是Sun官方在JDK5.0后提出的Java持久化规范（JSR 338，这些接口所在包为<code>javax.persistence</code>，详细内容可参考<a href="https://github.com/javaee/jpa-spec" target="_blank" rel="noopener noreferrer">https://github.com/javaee/jpa-spec<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a>）</p><p>JPA的出现主要是为了简化持久层开发以及整合<code>ORM</code>技术，结束 <code>Hibernate</code>、<code>TopLink</code>、<code>JDO</code>等<code>ORM</code>框架各自为营的局面。<code>JPA</code>是在吸收现有<code>ORM</code>框架的基础上发展而来，易于使用，伸缩性强。总的来说，JPA包括以下3方面的技术：</p><ul><li><strong>ORM映射元数据：</strong> 支持XML和注解两种元数据的形式，元数据描述对象和表之间的映射关系</li><li><strong>API：</strong> 操作实体对象来执行CRUD操作</li><li><strong>查询语言：</strong> 通过面向对象而非面向数据库的查询语言（JPQL）查询数据，避免程序的SQL语句紧密耦合</li></ul><p><img src="/eurynome-cloud/images/jpa/architecture.png" alt="JPA架构"></p><h3 id="spring-data-jpa-1" tabindex="-1"><a class="header-anchor" href="#spring-data-jpa-1" aria-hidden="true">#</a> Spring Data Jpa</h3><p>Spring官方的解释<a href="https://spring.io/projects/spring-data-jpa#overview" target="_blank" rel="noopener noreferrer">https://spring.io/projects/spring-data-jpa#overview<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a></p><p><img src="/eurynome-cloud/images/jpa/spring-data-jpa.png" alt="Spring Data Jpa官方解释"></p><p><code>Spring Data JPA</code> 是 <code>Spring Data</code> 家族的一部分，可以轻松实现基于 <code>JPA</code> 的存储库。 此模块处理对基于 <code>JPA</code> 的数据访问层的增强支持。 它使构建使用数据访问技术的Spring驱动应用程序变得更加容易。</p><p>在相当长的一段时间内，实现应用程序的数据访问层一直很麻烦。 必须编写太多样板代码来执行简单查询以及执行分页和审计。 <code>Spring Data JPA</code> 旨在通过减少实际需要的工作量来显著改善数据访问层的实现。 作为开发人员，您编写repository接口，包括自定义查找器方法，Spring将自动提供实现。</p><p><img src="/eurynome-cloud/images/jpa/spring-data.png" alt="Spring Data生态"></p><h3 id="jpa、hibernate、spring-data-jpa三者之间的关系" tabindex="-1"><a class="header-anchor" href="#jpa、hibernate、spring-data-jpa三者之间的关系" aria-hidden="true">#</a> Jpa、Hibernate、Spring Data Jpa三者之间的关系</h3><p>这个问题可参考<a href="https://stackoverflow.com/questions/16148188/spring-data-jpa-versus-jpa-whats-the-difference%E5%8F%8Ahttps://blog.csdn.net/u014421556/article/details/52635000" target="_blank" rel="noopener noreferrer">https://stackoverflow.com/questions/16148188/spring-data-jpa-versus-jpa-whats-the-difference及https://blog.csdn.net/u014421556/article/details/52635000<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a></p><p>总的来说<code>JPA</code>是<code>ORM</code>规范，<code>Hibernate</code>、<code>TopLink</code> 等是 <code>JPA</code> 规范的具体实现，这样的好处是开发者可以面向 <code>JPA</code> 规范进行持久层的开发，而底层的实现则是可以切换的。<code>Spring Data Jpa</code> 则是在 <code>JPA</code> 之上添加另一层抽象（<code>Repository</code>层的实现），极大地简化持久层开发及 <code>ORM</code> 框架切换的成本。</p><p><img src="/eurynome-cloud/images/jpa/three-relationship.png" alt="Jpa、Hibernate、Spring Data Jpa三者之间的关系"></p><h3 id="spring-data-jpa的java配置方案" tabindex="-1"><a class="header-anchor" href="#spring-data-jpa的java配置方案" aria-hidden="true">#</a> Spring Data Jpa的java配置方案</h3><p>在 <code>Spring Boot</code> 没出来之前如果要采用 <code>Java Configuration</code> 来配置 <code>Spring Data Jpa</code> 你需要配置如下的Bean 参考自Spring In Action及<a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.java-config" target="_blank" rel="noopener noreferrer">Spring Data Jpa官方文档5.1.2. Annotation-based Configuration<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Bean</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>context<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Configuration</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span>repository<span class="token punctuation">.</span>config<span class="token punctuation">.</span></span><span class="token class-name">EnableJpaRepositories</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>orm<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span></span><span class="token class-name">JpaTransactionManager</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>orm<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span></span><span class="token class-name">JpaVendorAdapter</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>orm<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span></span><span class="token class-name">LocalContainerEntityManagerFactoryBean</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>orm<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span>vendor<span class="token punctuation">.</span></span><span class="token class-name">Database</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>orm<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span>vendor<span class="token punctuation">.</span></span><span class="token class-name">HibernateJpaVendorAdapter</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>transaction<span class="token punctuation">.</span></span><span class="token class-name">PlatformTransactionManager</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>transaction<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">EnableTransactionManagement</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span></span><span class="token class-name">EntityManagerFactory</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>sql<span class="token punctuation">.</span></span><span class="token class-name">DataSource</span><span class="token punctuation">;</span>

<span class="token doc-comment comment">/**
 * 注意：spring-data-jpa2.x版本需要spring版本为5.x
 * 否则会报Initialization of bean failed; nested exception is java.lang.AbstractMethodError错误
 * 参考：https://stackoverflow.com/questions/47558017/error-starting-a-spring-application-initialization-of-bean-failed-nested-excep
 * 搭配方案：spring4+spring-data-jpa1.x或spring5+spring-data-jpa2.x
 */</span>
<span class="token annotation punctuation">@Configuration</span>
<span class="token comment">// 借助spring data实现自动化的jpa repository，只需编写接口无需编写实现类</span>
<span class="token comment">// 相当于xml配置的&lt;jpa:repositories base-package=&quot;com.example.repository&quot; /&gt;</span>
<span class="token comment">// repositoryImplementationPostfix默认就是Impl</span>
<span class="token comment">// entityManagerFactoryRef默认就是entityManagerFactory</span>
<span class="token comment">// transactionManagerRef默认就是transactionManager</span>
<span class="token annotation punctuation">@EnableJpaRepositories</span><span class="token punctuation">(</span>basePackages <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">&quot;com.example.repository&quot;</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
        repositoryImplementationPostfix <span class="token operator">=</span> <span class="token string">&quot;Impl&quot;</span><span class="token punctuation">,</span>
        entityManagerFactoryRef <span class="token operator">=</span> <span class="token string">&quot;entityManagerFactory&quot;</span><span class="token punctuation">,</span>
        transactionManagerRef <span class="token operator">=</span> <span class="token string">&quot;transactionManager&quot;</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@EnableTransactionManagement</span>    <span class="token comment">// 启用事务管理器</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SpringDataJpaConfig</span> <span class="token punctuation">{</span>

    <span class="token comment">// 配置jpa厂商适配器（参见spring实战p320）</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">JpaVendorAdapter</span> <span class="token function">jpaVendorAdapter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">HibernateJpaVendorAdapter</span> jpaVendorAdapter <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">HibernateJpaVendorAdapter</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 设置数据库类型（可使用org.springframework.orm.jpa.vendor包下的Database枚举类）</span>
        jpaVendorAdapter<span class="token punctuation">.</span><span class="token function">setDatabase</span><span class="token punctuation">(</span><span class="token class-name">Database</span><span class="token punctuation">.</span>MYSQL<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 设置打印sql语句</span>
        jpaVendorAdapter<span class="token punctuation">.</span><span class="token function">setShowSql</span><span class="token punctuation">(</span><span class="token boolean">true</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 设置不生成ddl语句</span>
        jpaVendorAdapter<span class="token punctuation">.</span><span class="token function">setGenerateDdl</span><span class="token punctuation">(</span><span class="token boolean">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 设置hibernate方言</span>
        jpaVendorAdapter<span class="token punctuation">.</span><span class="token function">setDatabasePlatform</span><span class="token punctuation">(</span><span class="token string">&quot;org.hibernate.dialect.MySQL5Dialect&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> jpaVendorAdapter<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 配置实体管理器工厂</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">LocalContainerEntityManagerFactoryBean</span> <span class="token function">entityManagerFactory</span><span class="token punctuation">(</span>
            <span class="token class-name">DataSource</span> dataSource<span class="token punctuation">,</span> <span class="token class-name">JpaVendorAdapter</span> jpaVendorAdapter<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">LocalContainerEntityManagerFactoryBean</span> emfb <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LocalContainerEntityManagerFactoryBean</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 注入数据源</span>
        emfb<span class="token punctuation">.</span><span class="token function">setDataSource</span><span class="token punctuation">(</span>dataSource<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 注入jpa厂商适配器</span>
        emfb<span class="token punctuation">.</span><span class="token function">setJpaVendorAdapter</span><span class="token punctuation">(</span>jpaVendorAdapter<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 设置扫描基本包</span>
        emfb<span class="token punctuation">.</span><span class="token function">setPackagesToScan</span><span class="token punctuation">(</span><span class="token string">&quot;com.example.entity&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> emfb<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 配置jpa事务管理器</span>
    <span class="token annotation punctuation">@Bean</span>
    <span class="token keyword">public</span> <span class="token class-name">PlatformTransactionManager</span> <span class="token function">transactionManager</span><span class="token punctuation">(</span><span class="token class-name">EntityManagerFactory</span> emf<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">JpaTransactionManager</span> transactionManager <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">JpaTransactionManager</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 配置实体管理器工厂</span>
        transactionManager<span class="token punctuation">.</span><span class="token function">setEntityManagerFactory</span><span class="token punctuation">(</span>emf<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> transactionManager<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br><span class="line-number">70</span><br><span class="line-number">71</span><br><span class="line-number">72</span><br></div></div><p>启用web支持还需要在 <code>Spring MVC</code> 配置类上添加 <code>@EnableSpringDataWebSupport</code> 注解</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Configuration</span>
<span class="token annotation punctuation">@ComponentScan</span><span class="token punctuation">(</span>basePackages <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token string">&quot;cn.fulgens.controller&quot;</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@EnableWebMvc</span>   <span class="token comment">// 启用spring mvc</span>
<span class="token annotation punctuation">@EnableSpringDataWebSupport</span>     <span class="token comment">// 启用springmvc对spring data的支持</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">WebMvcConfig</span> <span class="token keyword">extends</span> <span class="token class-name">WebMvcConfigurerAdapter</span> <span class="token punctuation">{</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h3 id="spring-boot整合spring-data-jpa" tabindex="-1"><a class="header-anchor" href="#spring-boot整合spring-data-jpa" aria-hidden="true">#</a> Spring Boot整合Spring Data Jpa</h3><h4 id="导入依赖" tabindex="-1"><a class="header-anchor" href="#导入依赖" aria-hidden="true">#</a> 导入依赖</h4><div class="language-xml ext-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-web<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-data-jpa<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>mysql<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>mysql-connector-java<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>scope</span><span class="token punctuation">&gt;</span></span>runtime<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>scope</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.projectlombok<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>lombok<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>optional</span><span class="token punctuation">&gt;</span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>optional</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-devtools<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>optional</span><span class="token punctuation">&gt;</span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>optional</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dependency</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>groupId</span><span class="token punctuation">&gt;</span></span>org.springframework.boot<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>groupId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>artifactId</span><span class="token punctuation">&gt;</span></span>spring-boot-starter-test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>artifactId</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>scope</span><span class="token punctuation">&gt;</span></span>test<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>scope</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dependency</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br></div></div><h4 id="相关配置" tabindex="-1"><a class="header-anchor" href="#相关配置" aria-hidden="true">#</a> 相关配置</h4><div class="language-yaml ext-yml line-numbers-mode"><pre class="language-yaml"><code><span class="token key atrule">server</span><span class="token punctuation">:</span>
  <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">8080</span>
  <span class="token key atrule">servlet</span><span class="token punctuation">:</span>
    <span class="token key atrule">context-path</span><span class="token punctuation">:</span> /
<span class="token key atrule">spring</span><span class="token punctuation">:</span>
  <span class="token key atrule">datasource</span><span class="token punctuation">:</span>
    <span class="token key atrule">url</span><span class="token punctuation">:</span> jdbc<span class="token punctuation">:</span>mysql<span class="token punctuation">:</span>//localhost<span class="token punctuation">:</span>3306/test<span class="token punctuation">?</span>useUnicode=true<span class="token important">&amp;characterEncoding=UTF-8&amp;zeroDateTimeBehavior=convertToNull&amp;allowMultiQueries=true&amp;useSSL=false</span>
    <span class="token key atrule">username</span><span class="token punctuation">:</span> root
    <span class="token key atrule">password</span><span class="token punctuation">:</span> mysql123
  <span class="token key atrule">jpa</span><span class="token punctuation">:</span>
    <span class="token key atrule">database</span><span class="token punctuation">:</span> MySQL
    <span class="token key atrule">database-platform</span><span class="token punctuation">:</span> org.hibernate.dialect.MySQL5InnoDBDialect
    <span class="token key atrule">show-sql</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
    <span class="token key atrule">hibernate</span><span class="token punctuation">:</span>
      <span class="token key atrule">ddl-auto</span><span class="token punctuation">:</span> update
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><div class="custom-container tip"><p class="custom-container-title">ddl-auto</p><ul><li>create：每次运行程序时，都会重新创建表，故而数据会丢失</li><li>create-drop：每次运行程序时会先创建表结构，然后待程序结束时清空表</li><li>upadte：每次运行程序，没有表时会创建表，如果对象发生改变会更新表结构，原有数据不会清空，只会更新（推荐使用）</li><li>validate：运行程序会校验数据与数据库的字段类型是否相同，字段不同会报错</li><li>none: 禁用DDL处理</li></ul></div><h2 id="spring-data-jpa的使用" tabindex="-1"><a class="header-anchor" href="#spring-data-jpa的使用" aria-hidden="true">#</a> Spring Data Jpa的使用</h2><h3 id="spring-data-jpa-uml类图" tabindex="-1"><a class="header-anchor" href="#spring-data-jpa-uml类图" aria-hidden="true">#</a> Spring Data Jpa UML类图</h3><p><img src="/eurynome-cloud/images/jpa/spring-data-jpa-uml.png" alt="Spring Data JPA UML"></p><h3 id="简单的rest-crud示例" tabindex="-1"><a class="header-anchor" href="#简单的rest-crud示例" aria-hidden="true">#</a> 简单的REST CRUD示例</h3><p><strong>实体类</strong></p><p><code>/src/main/java/com/example/springbootjpa/entity/User</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Data</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>annotations<span class="token punctuation">.</span></span><span class="token class-name">GenericGenerator</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Entity</span>
<span class="token annotation punctuation">@Table</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;tb_user&quot;</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Id</span>
    <span class="token annotation punctuation">@GenericGenerator</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">,</span> strategy <span class="token operator">=</span> <span class="token string">&quot;uuid&quot;</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@GeneratedValue</span><span class="token punctuation">(</span>generator <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> id<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;username&quot;</span><span class="token punctuation">,</span> unique <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> username<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;password&quot;</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> password<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;email&quot;</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> email<span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br></div></div><div class="custom-container tip"><p class="custom-container-title">主键采用UUID策略</p><p><code>@GenericGenerator</code> 是 <code>Hibernate</code> 提供的主键生成策略注解，注意下面的 <code>@GeneratedValue</code>（JPA注解）使用<code>generator = &quot;idGenerator&quot;</code>引用了上面的<code>name = &quot;idGenerator&quot;</code>主键生成策略</p></div><p>一般简单的Demo示例中只会使用<code>@GeneratedValue(strategy = GenerationType.IDENTITY)</code>这种主键自增的策略，而实际数据库中表字段主键类型很少是<code>int</code>型的</p><div class="custom-container tip"><p class="custom-container-title">JPA自带的几种主键生成策略</p><ul><li>TABLE： 使用一个特定的数据库表格来保存主键</li><li>SEQUENCE： 根据底层数据库的序列来生成主键，条件是数据库支持序列。这个值要与generator一起使用，generator 指定生成主键使用的生成器（可能是orcale中自己编写的序列）</li><li>IDENTITY： 主键由数据库自动生成（主要是支持自动增长的数据库，如mysql）</li><li>AUTO： 主键由程序控制，也是GenerationType的默认值</li></ul></div><p><strong>Dao层</strong></p><p><code>/src/main/java/com/example/springbootjpa/repository/UserRepository</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>repository</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity<span class="token punctuation">.</span></span><span class="token class-name">User</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span>repository<span class="token punctuation">.</span></span><span class="token class-name">JpaRepository</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">UserRepository</span> <span class="token keyword">extends</span> <span class="token class-name">JpaRepository</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p><strong>Controller层</strong></p><blockquote><p>这里简单起见省略Service层</p></blockquote><p><code>/src/main/java/com/example/springbootjpa/controller/UserController</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>controller</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity<span class="token punctuation">.</span></span><span class="token class-name">User</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>repository<span class="token punctuation">.</span></span><span class="token class-name">UserRepository</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>beans<span class="token punctuation">.</span>factory<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">Autowired</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>domain<span class="token punctuation">.</span></span><span class="token class-name">Page</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>domain<span class="token punctuation">.</span></span><span class="token class-name">PageRequest</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>domain<span class="token punctuation">.</span></span><span class="token class-name">Pageable</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>web<span class="token punctuation">.</span>bind<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">HashMap</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Optional</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@RestController</span>
<span class="token annotation punctuation">@RequestMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/users&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserController</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Autowired</span>
    <span class="token keyword">private</span> <span class="token class-name">UserRepository</span> userRepository<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@PostMapping</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">User</span> <span class="token function">saveUser</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestBody</span> <span class="token class-name">User</span> user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> userRepository<span class="token punctuation">.</span><span class="token function">save</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@DeleteMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/{id}&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">deleteUser</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span><span class="token punctuation">(</span><span class="token string">&quot;id&quot;</span><span class="token punctuation">)</span> <span class="token class-name">String</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        userRepository<span class="token punctuation">.</span><span class="token function">deleteById</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@PutMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/{id}&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">User</span> <span class="token function">updateUser</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span><span class="token punctuation">(</span><span class="token string">&quot;id&quot;</span><span class="token punctuation">)</span> <span class="token class-name">String</span> userId<span class="token punctuation">,</span> <span class="token annotation punctuation">@RequestBody</span> <span class="token class-name">User</span> user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        user<span class="token punctuation">.</span><span class="token function">setId</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> userRepository<span class="token punctuation">.</span><span class="token function">saveAndFlush</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/{id}&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">User</span> <span class="token function">getUserInfo</span><span class="token punctuation">(</span><span class="token annotation punctuation">@PathVariable</span><span class="token punctuation">(</span><span class="token string">&quot;id&quot;</span><span class="token punctuation">)</span> <span class="token class-name">String</span> userId<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">Optional</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> optional <span class="token operator">=</span> userRepository<span class="token punctuation">.</span><span class="token function">findById</span><span class="token punctuation">(</span>userId<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> optional<span class="token punctuation">.</span><span class="token function">orElseGet</span><span class="token punctuation">(</span><span class="token class-name">User</span><span class="token operator">::</span><span class="token keyword">new</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@GetMapping</span><span class="token punctuation">(</span><span class="token string">&quot;/list&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">public</span> <span class="token class-name">Page</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">pageQuery</span><span class="token punctuation">(</span><span class="token annotation punctuation">@RequestParam</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">&quot;pageNum&quot;</span><span class="token punctuation">,</span> defaultValue <span class="token operator">=</span> <span class="token string">&quot;1&quot;</span><span class="token punctuation">)</span> <span class="token class-name">Integer</span> pageNum<span class="token punctuation">,</span>
                                <span class="token annotation punctuation">@RequestParam</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">&quot;pageSize&quot;</span><span class="token punctuation">,</span> defaultValue <span class="token operator">=</span> <span class="token string">&quot;10&quot;</span><span class="token punctuation">)</span> <span class="token class-name">Integer</span> pageSize<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> userRepository<span class="token punctuation">.</span><span class="token function">findAll</span><span class="token punctuation">(</span><span class="token class-name">PageRequest</span><span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span>pageNum <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">,</span> pageSize<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br></div></div><h2 id="spring-data-jpa使用详解" tabindex="-1"><a class="header-anchor" href="#spring-data-jpa使用详解" aria-hidden="true">#</a> Spring Data Jpa使用详解</h2><h3 id="spring-data查询方法" tabindex="-1"><a class="header-anchor" href="#spring-data查询方法" aria-hidden="true">#</a> Spring Data查询方法</h3><p>使用Spring Data创建查询只需四步：</p><ol><li>声明一个接口继承自Repository或Repositoy的一个子接口，对于Spring Data Jpa通常是JpaRepository，如：</li></ol><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">interface</span> <span class="token class-name">PersonRepository</span> <span class="token keyword">extends</span> <span class="token class-name">Repository</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Person</span><span class="token punctuation">,</span> <span class="token class-name">Long</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span> … <span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br></div></div><ol start="2"><li>在接口中声明查询方法，如：</li></ol><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">interface</span> <span class="token class-name">PersonRepository</span> <span class="token keyword">extends</span> <span class="token class-name">Repository</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Person</span><span class="token punctuation">,</span> <span class="token class-name">Long</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
  <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Person</span><span class="token punctuation">&gt;</span></span> <span class="token function">findByLastname</span><span class="token punctuation">(</span><span class="token class-name">String</span> lastname<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><ol start="3"><li>使用 <a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.create-instances.java-config" target="_blank" rel="noopener noreferrer">JavaConfig<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a> 或 <a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.create-instances" target="_blank" rel="noopener noreferrer">XML configuration<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a>配置Spring，让 Spring 为声明的接口创建代理对象 3.1 JavaConfig参见上文 3.2 使用Xml配置，可以像下面这样使用jpa命名空间进行配置：</li></ol><div class="language-xml ext-xml line-numbers-mode"><pre class="language-xml"><code><span class="token prolog">&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>beans</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.springframework.org/schema/beans<span class="token punctuation">&quot;</span></span>
   <span class="token attr-name"><span class="token namespace">xmlns:</span>xsi</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.w3.org/2001/XMLSchema-instance<span class="token punctuation">&quot;</span></span>
   <span class="token attr-name"><span class="token namespace">xmlns:</span>jpa</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.springframework.org/schema/data/jpa<span class="token punctuation">&quot;</span></span>
   <span class="token attr-name"><span class="token namespace">xsi:</span>schemaLocation</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>http://www.springframework.org/schema/beans
     http://www.springframework.org/schema/beans/spring-beans.xsd
     http://www.springframework.org/schema/data/jpa
     http://www.springframework.org/schema/data/jpa/spring-jpa.xsd<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>

   <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span><span class="token namespace">jpa:</span>repositories</span> <span class="token attr-name">base-package</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>com.acme.repositories<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>beans</span><span class="token punctuation">&gt;</span></span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><blockquote><p>对于不同的 <code>Spring Data</code> 子项目Spring提供了不同的xml命名空间，如对于 <code>Spring Data MongoDB</code> 可以将上面的jpa改为mongodb。当然，使用 <code>Spring Boot</code> 这一步基本可以省略，我们需要做的就是在<code>application.properties</code>或<code>application.yml</code>文件中配置几个属性即可</p></blockquote><ol start="4"><li>注入Repository实例并使用，如：</li></ol><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">class</span> <span class="token class-name">SomeClient</span> <span class="token punctuation">{</span>

  <span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token class-name">PersonRepository</span> repository<span class="token punctuation">;</span>

  <span class="token class-name">SomeClient</span><span class="token punctuation">(</span><span class="token class-name">PersonRepository</span> repository<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">this</span><span class="token punctuation">.</span>repository <span class="token operator">=</span> repository<span class="token punctuation">;</span>
  <span class="token punctuation">}</span>

  <span class="token keyword">void</span> <span class="token function">doSomething</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Person</span><span class="token punctuation">&gt;</span></span> persons <span class="token operator">=</span> repository<span class="token punctuation">.</span><span class="token function">findByLastname</span><span class="token punctuation">(</span><span class="token string">&quot;Matthews&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
  <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h4 id="定义repository接口" tabindex="-1"><a class="header-anchor" href="#定义repository接口" aria-hidden="true">#</a> 定义Repository接口</h4><p><strong>选择性暴露CRUD方法</strong></p><p>一种方法是定义一个<code>BaseRepository</code>接口继承<code>Repository</code>接口，并从<code>CrudRepository</code>中copy你想暴露的CRUD方法</p><p><code>src/main/java/com/example/springbootjpa/repository/MyBaseRepository</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>repository</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>repository<span class="token punctuation">.</span></span><span class="token class-name">NoRepositoryBean</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>repository<span class="token punctuation">.</span></span><span class="token class-name">Repository</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Optional</span><span class="token punctuation">;</span>

<span class="token doc-comment comment">/**
 * 自定义Repository，选择性暴露CRUD方法
 * <span class="token keyword">@param</span> <span class="token class-name"><span class="token punctuation">&lt;</span>T<span class="token punctuation">&gt;</span></span>
 * <span class="token keyword">@param</span> <span class="token class-name"><span class="token punctuation">&lt;</span>ID<span class="token punctuation">&gt;</span></span>
 */</span>
<span class="token annotation punctuation">@NoRepositoryBean</span>
<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">MyBaseRepository</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">,</span> ID<span class="token punctuation">&gt;</span></span> <span class="token keyword">extends</span> <span class="token class-name">Repository</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">,</span> ID<span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>

    <span class="token class-name">Optional</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token function">findById</span><span class="token punctuation">(</span><span class="token class-name">ID</span> id<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">S</span> <span class="token keyword">extends</span> <span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token class-name">S</span> <span class="token function">save</span><span class="token punctuation">(</span><span class="token class-name">S</span> entity<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><blockquote><p>注意：<code>MyBaseRepository</code>上面加了 <code>@NoRepositoryBean</code> 注解</p></blockquote><p><code>src/main/java/com/example/springbootjpa/repository/UserRepository2</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>repository</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity<span class="token punctuation">.</span></span><span class="token class-name">User</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Repository</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">UserRepository2</span> <span class="token keyword">extends</span> <span class="token class-name">MyBaseRepository</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">,</span> <span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h4 id="repository方法的null值处理" tabindex="-1"><a class="header-anchor" href="#repository方法的null值处理" aria-hidden="true">#</a> Repository方法的Null值处理</h4><p>从 <code>Spring Data2.0</code> 开始对于返回单个聚合实例的CRUD方法可以使用java8 Optional接口作为方法返回值来表明可能存在的缺省值，典型示例为 <code>CrudRepository</code> 的 <code>findById</code> 方法</p><p>另外Spring也提供了几个注解来处理Null值</p><ul><li>@NonNullApi: 在包级别使用来声明参数和返回值不能为Null</li><li>@NonNull: 在参数或返回值上使用，当它们不能为Null时（如果在包级别上使用了@NonNullApi注解则没有必要再使用@NonNull注解了）</li><li>@Nullable: 在参数或返回值上使用，当它们可以为Null时</li></ul><h3 id="查询方法" tabindex="-1"><a class="header-anchor" href="#查询方法" aria-hidden="true">#</a> 查询方法</h3><h4 id="查询创建query-creation" tabindex="-1"><a class="header-anchor" href="#查询创建query-creation" aria-hidden="true">#</a> 查询创建Query Creation</h4><p><code>Spring Data Jpa</code> 通过解析方法名创建查询，框架在进行方法名解析时，会先把方法名多余的前缀<code>find…By</code>, <code>read…By</code>, <code>query…By</code>, <code>count…By</code>以及 <code>get…By</code> 截取掉，然后对剩下部分进行解析，第一个By会被用作分隔符来指示实际查询条件的开始。 我们可以在实体属性上定义条件，并将它们与And和Or连接起来，从而创建大量查询：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">User</span> <span class="token function">findByUsername</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findByUsernameIgnoreCase</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findByUsernameLike</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">User</span> <span class="token function">findByUsernameAndPassword</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">User</span> <span class="token function">findByEmail</span><span class="token punctuation">(</span><span class="token class-name">String</span> email<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findByEmailLike</span><span class="token punctuation">(</span><span class="token class-name">String</span> email<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findByIdIn</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> ids<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findByIdInOrderByUsername</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> ids<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">void</span> <span class="token function">deleteByIdIn</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> ids<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">Long</span> <span class="token function">countByUsernameLike</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><p>支持的关键字、示例及 <code>JPQL</code> 片段如下表所示：</p><p>| Keyword | Sample | JPQL snippet | | ------- | ------ | ------------ || | <code>Distinct</code> | <code>findDistinctByLastnameAndFirstname</code> | <code>select distinct …​ where x.lastname = ?1 and x.firstname = ?2</code> | | <code>And</code> | <code>findByLastnameAndFirstname</code> | <code>… where x.lastname = ?1 and x.firstname = ?2</code> | | <code>Or</code> | <code>findByLastnameOrFirstname</code> | <code>… where x.lastname = ?1 or x.firstname = ?2</code> | | <code>Is, Equals</code> | <code>findByFirstname</code>,<code>findByFirstnameIs</code>,<code>findByFirstnameEquals</code> | <code>… where x.firstname = ?</code>1 | | <code>Between</code> | <code>findByStartDateBetween</code> | <code>… where x.startDate between ?1 and ?2</code> | | <code>LessThan</code> | <code>findByAgeLessThan</code> | <code>… where x.age &lt; ?1</code> | | <code>LessThanEqual</code> | <code>findByAgeLessThanEqual</code> | <code>… where x.age &lt;= ?1</code> | | <code>GreaterThan</code> | <code>findByAgeGreaterThan</code> | <code>… where x.age &gt; ?1</code> | | <code>GreaterThanEqual</code> | <code>findByAgeGreaterThanEqual</code> | <code>… where x.age &gt;= ?1</code> | | <code>After</code> | <code>findByStartDateAfter</code> | <code>… where x.startDate &gt; ?1</code> | | <code>Before</code> | <code>findByStartDateBefore</code> | <code>… where x.startDate &lt; ?1</code> | | <code>IsNull, Null</code> | <code>findByAge(Is)Null</code> | <code>… where x.age is null</code> | | <code>IsNotNull, NotNull</code> | <code>findByAge(Is)NotNull</code> | <code>… where x.age not null</code> | | <code>Like</code> | <code>findByFirstnameLike</code> | <code>… where x.firstname like ?1</code> | | <code>NotLike</code> | <code>findByFirstnameNotLike</code> | <code>… where x.firstname not like ?1</code> | | <code>StartingWith</code> | <code>findByFirstnameStartingWith</code> |<code>… where x.firstname like ?1 (parameter bound with appended %)</code> | | <code>EndingWith</code> | <code>findByFirstnameEndingWith</code> | <code>… where x.firstname like ?1 (parameter bound with prepended %)</code> | | <code>Containing</code> | <code>findByFirstnameContaining</code> | <code>… where x.firstname like ?1 (parameter bound wrapped in %)</code> | | <code>OrderBy</code> | <code>findByAgeOrderByLastnameDesc</code> | <code>… where x.age = ?1 order by x.lastname desc</code> | | <code>Not</code> | <code>findByLastnameNot</code> | <code>… where x.lastname &lt;&gt; ?1</code> | | <code>In</code> | <code>findByAgeIn(Collection&lt;Age&gt; ages)</code> | <code>… where x.age in ?1</code> | | <code>NotIn</code> | <code>findByAgeNotIn(Collection&lt;Age&gt; ages)</code> | <code>… where x.age not in ?1</code> | | <code>True</code> | <code>findByActiveTrue()</code> | <code>… where x.active = true</code> | | <code>False</code> | <code>findByActiveFalse()</code> | <code>… where x.active = false</code> | | <code>IgnoreCase</code> | <code>findByFirstnameIgnoreCase</code> | <code>… where UPPER(x.firstname) = UPPER(?1)</code> |</p><p>具体 <code>Spring Data Jpa</code> 对方法名的解析规则可参看<a href="https://docs.spring.io/spring-data/jpa/docs/2.5.4/reference/html/#reference" target="_blank" rel="noopener noreferrer">官方文档<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a></p><h4 id="限制查询结果" tabindex="-1"><a class="header-anchor" href="#限制查询结果" aria-hidden="true">#</a> 限制查询结果</h4><p><code>Spring Data Jpa</code> 支持使用<code>first</code>、<code>top</code> 以及 <code>Distinct</code> 关键字来限制查询结果，如：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">User</span> <span class="token function">findFirstByUsernameOrderByUsernameAsc</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findTop10ByUsername</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">Sort</span> sort<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findTop10ByUsername</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">Pageable</span> pageable<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h4 id="自定义查询using-query" tabindex="-1"><a class="header-anchor" href="#自定义查询using-query" aria-hidden="true">#</a> 自定义查询Using @Query</h4><p><code>@Query</code> 注解的使用非常简单，只需在声明的方法上面标注该注解，同时提供一个 <code>JPQL</code> 查询语句即可</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;select u from User u where u.email = ?1&quot;</span><span class="token punctuation">)</span>
<span class="token class-name">User</span> <span class="token function">getByEmail</span><span class="token punctuation">(</span><span class="token class-name">String</span> eamil<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;select u from User u where u.username = ?1 and u.password = ?2&quot;</span><span class="token punctuation">)</span>
<span class="token class-name">User</span> <span class="token function">getByUsernameAndPassword</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;select u from User u where u.username like %?1%&quot;</span><span class="token punctuation">)</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">getByUsernameLike</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h4 id="使用命名参数using-named-parameters" tabindex="-1"><a class="header-anchor" href="#使用命名参数using-named-parameters" aria-hidden="true">#</a> 使用命名参数Using Named Parameters</h4><p>默认情况下，<code>Spring Data JPA</code> 使用基于位置的参数绑定，如前面所有示例中所述。 这使得查询方法在重构参数位置时容易出错。 要解决此问题，可以使用 <code>@Param</code> 注解为方法参数指定具体名称并在查询中绑定名称，如以下示例所示：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;select u from User u where u.id = :id&quot;</span><span class="token punctuation">)</span>
<span class="token class-name">User</span> <span class="token function">getById</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">&quot;id&quot;</span><span class="token punctuation">)</span> <span class="token class-name">String</span> userId<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;select u from User u where u.username = :username or u.email = :email&quot;</span><span class="token punctuation">)</span>
<span class="token class-name">User</span> <span class="token function">getByUsernameOrEmail</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span> <span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">&quot;email&quot;</span><span class="token punctuation">)</span> <span class="token class-name">String</span> email<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h4 id="using-spel-expressions" tabindex="-1"><a class="header-anchor" href="#using-spel-expressions" aria-hidden="true">#</a> Using SpEL Expressions</h4><p>从 <code>Spring Data JPA release 1.4</code> 开始，<code>Spring Data JPA</code> 支持名为 <code>entityName</code> 的变量。 它的用法是<code>select x from #{#entityName} x</code>。</p><p><code>entityName</code>的解析方式如下：如果实体类在 <code>@Entity</code> 注解上设置了<code>name</code>属性，则使用它。否则，使用实体类的简单类名。为避免在 <code>@Query</code> 注解使用实际的实体类名，就可以使用<code>#{#entityName}</code>进行代替。如以上示例中，<code>@Query</code>注解的查询字符串里的User都可替换为<code>#{#entityName}</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;select u from #{#entityName} u where u.email = ?1&quot;</span><span class="token punctuation">)</span>
<span class="token class-name">User</span> <span class="token function">getByEmail</span><span class="token punctuation">(</span><span class="token class-name">String</span> eamil<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="原生查询native-queries" tabindex="-1"><a class="header-anchor" href="#原生查询native-queries" aria-hidden="true">#</a> 原生查询Native Queries</h4><p><code>@Query</code> 注解还支持通过将 <code>nativeQuery</code> 标志设置为<code>true</code>来执行原生查询，同样支持基于位置的参数绑定及命名参数，如：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">&quot;select * from tb_user u where u.email = ?1&quot;</span><span class="token punctuation">,</span> nativeQuery <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
<span class="token class-name">User</span> <span class="token function">queryByEmail</span><span class="token punctuation">(</span><span class="token class-name">String</span> email<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">&quot;select * from tb_user u where u.email = :email&quot;</span><span class="token punctuation">,</span> nativeQuery <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
<span class="token class-name">User</span> <span class="token function">queryByEmail</span><span class="token punctuation">(</span><span class="token annotation punctuation">@Param</span><span class="token punctuation">(</span><span class="token string">&quot;email&quot;</span><span class="token punctuation">)</span> <span class="token class-name">String</span> email<span class="token punctuation">)</span><span class="token punctuation">;</span>
注意：<span class="token class-name">Spring</span> <span class="token class-name">Data</span> <span class="token class-name">Jpa</span>目前不支持对原生查询进行动态排序，但可以通过自己指定计数查询countQuery来使用原生查询进行分页、排序，如：

<span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span>value <span class="token operator">=</span> <span class="token string">&quot;select * from tb_user u where u.username like %?1%&quot;</span><span class="token punctuation">,</span>
            countQuery <span class="token operator">=</span> <span class="token string">&quot;select count(1) from tb_user u where u.username = %?1%&quot;</span><span class="token punctuation">,</span>
            nativeQuery <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">)</span>
<span class="token class-name">Page</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">queryByUsernameLike</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">Pageable</span> pageable<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><h4 id="分页查询及排序" tabindex="-1"><a class="header-anchor" href="#分页查询及排序" aria-hidden="true">#</a> 分页查询及排序</h4><p><code>Spring Data Jpa</code> 可以在方法参数中直接传入<code>Pageable</code> 或 <code>Sort</code> 来完成动态分页或排序，通常 <code>Pageable</code> 或 <code>Sort</code> 会是方法的最后一个参数，如：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;select u from User u where u.username like %?1%&quot;</span><span class="token punctuation">)</span>
<span class="token class-name">Page</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findByUsernameLike</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">Pageable</span> pageable<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;select u from User u where u.username like %?1%&quot;</span><span class="token punctuation">)</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> <span class="token function">findByUsernameAndSort</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">Sort</span> sort<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>那调用<code>repository</code>方法时传入什么参数呢？</p><p>对于 <code>Pageable</code> 参数，在Spring Data 2.0之前我们可以new一个<code>org.springframework.data.domain.PageRequest</code>对象，现在这些构造方法已经废弃，取而代之Spring推荐我们使用 <code>PageRequest</code> 的 <code>of</code> 方法</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">new</span> <span class="token class-name">PageRequest</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">new</span> <span class="token class-name">PageRequest</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token class-name">Sort<span class="token punctuation">.</span>Direction</span><span class="token punctuation">.</span>ASC<span class="token punctuation">,</span> <span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">new</span> <span class="token class-name">PageRequest</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">Sort</span><span class="token punctuation">(</span><span class="token class-name">Sort<span class="token punctuation">.</span>Direction</span><span class="token punctuation">.</span>ASC<span class="token punctuation">,</span> <span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        
<span class="token class-name">PageRequest</span><span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">PageRequest</span><span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token class-name">Sort<span class="token punctuation">.</span>Direction</span><span class="token punctuation">.</span>ASC<span class="token punctuation">,</span> <span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">PageRequest</span><span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">,</span> <span class="token class-name">Sort</span><span class="token punctuation">.</span><span class="token function">by</span><span class="token punctuation">(</span><span class="token class-name">Sort<span class="token punctuation">.</span>Direction</span><span class="token punctuation">.</span>ASC<span class="token punctuation">,</span> <span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><blockquote><p>注意：<code>Spring Data PageRequest</code>的<code>page</code>参数是从<code>0</code>开始的 zero-based page index</p></blockquote><p>对于<code>Sort</code>参数，同样可以new一个<code>org.springframework.data.domain.Sort</code>，但推荐使用<code>Sort.by</code>方法</p><h4 id="自定义修改、删除-modifying-queries" tabindex="-1"><a class="header-anchor" href="#自定义修改、删除-modifying-queries" aria-hidden="true">#</a> 自定义修改、删除 Modifying Queries</h4><p>单独使用 <code>@Query</code> 注解只是查询，如涉及到修改、删除则需要再加上 <code>@Modifying</code> 注解，如：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Transactional</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Modifying</span>
<span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;update User u set u.password = ?2 where u.username = ?1&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">int</span> <span class="token function">updatePasswordByUsername</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">,</span> <span class="token class-name">String</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Transactional</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Modifying</span>
<span class="token annotation punctuation">@Query</span><span class="token punctuation">(</span><span class="token string">&quot;delete from User where username = ?1&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">void</span> <span class="token function">deleteByUsername</span><span class="token punctuation">(</span><span class="token class-name">String</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><blockquote><p>注意：Modifying queries can only use void or int/Integer as return type!</p></blockquote><h3 id="多表查询" tabindex="-1"><a class="header-anchor" href="#多表查询" aria-hidden="true">#</a> 多表查询</h3><p>这里使用级联查询进行多表的关联查询</p><h4 id="多对多" tabindex="-1"><a class="header-anchor" href="#多对多" aria-hidden="true">#</a> 多对多</h4><p><code>/src/main/java/com/example/springbootjpa/entity/User</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Data</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>annotations<span class="token punctuation">.</span></span><span class="token class-name">GenericGenerator</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Date</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Set</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span>UUID<span class="token punctuation">;</span>

<span class="token annotation punctuation">@Entity</span>
<span class="token annotation punctuation">@Table</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;tb_user&quot;</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Id</span>
    <span class="token annotation punctuation">@GenericGenerator</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">,</span> strategy <span class="token operator">=</span> <span class="token string">&quot;uuid&quot;</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@GeneratedValue</span><span class="token punctuation">(</span>generator <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> id<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;username&quot;</span><span class="token punctuation">,</span> unique <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> username<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;password&quot;</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> password<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;email&quot;</span><span class="token punctuation">,</span> unique <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> email<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@ManyToMany</span><span class="token punctuation">(</span>targetEntity <span class="token operator">=</span> <span class="token class-name">Role</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> cascade <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token class-name">CascadeType</span><span class="token punctuation">.</span>PERSIST<span class="token punctuation">,</span> <span class="token class-name">CascadeType</span><span class="token punctuation">.</span>MERGE<span class="token punctuation">}</span><span class="token punctuation">,</span> fetch <span class="token operator">=</span> <span class="token class-name">FetchType</span><span class="token punctuation">.</span>LAZY<span class="token punctuation">)</span>
    <span class="token annotation punctuation">@JoinTable</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;tb_user_role&quot;</span><span class="token punctuation">,</span> joinColumns <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token annotation punctuation">@JoinColumn</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;user_id&quot;</span><span class="token punctuation">,</span> referencedColumnName <span class="token operator">=</span> <span class="token string">&quot;id&quot;</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
            inverseJoinColumns <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token annotation punctuation">@JoinColumn</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;role_id&quot;</span><span class="token punctuation">,</span> referencedColumnName <span class="token operator">=</span> <span class="token string">&quot;id&quot;</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Role</span><span class="token punctuation">&gt;</span></span> roles<span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br></div></div><p><code>/src/main/java/com/example/springbootjpa/entity/Role</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Data</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>annotations<span class="token punctuation">.</span></span><span class="token class-name">GenericGenerator</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Entity</span>
<span class="token annotation punctuation">@Table</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;tb_role&quot;</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Role</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Id</span>
    <span class="token annotation punctuation">@GenericGenerator</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">,</span> strategy <span class="token operator">=</span> <span class="token string">&quot;uuid&quot;</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@GeneratedValue</span><span class="token punctuation">(</span>generator <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> id<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;role_name&quot;</span><span class="token punctuation">,</span> unique <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> roleName<span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br></div></div><p>测试</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">findByIdTest</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Optional</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">User</span><span class="token punctuation">&gt;</span></span> optional <span class="token operator">=</span> userRepository<span class="token punctuation">.</span><span class="token function">findById</span><span class="token punctuation">(</span><span class="token string">&quot;40289f0c65674a930165674d54940000&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Role</span><span class="token punctuation">&gt;</span></span> roles <span class="token operator">=</span> optional<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getRoles</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>optional<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>不出意外会报 <code>Hibernate</code> 懒加载异常，无法初始化代理类，No Session：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span></span>LazyInitializationException</span><span class="token operator">:</span> failed <span class="token keyword">to</span> <span class="token namespace">lazily</span> initialize a collection of role<span class="token operator">:</span> <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity<span class="token punctuation">.</span></span>User</span><span class="token punctuation">.</span>roles<span class="token punctuation">,</span> could not initialize proxy <span class="token operator">-</span> no <span class="token class-name">Session</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br></div></div><p>原因：<code>Spring Boot</code> 整合 <code>JPA</code> 后 <code>Hibernate</code> 的 <code>Session</code> 就交付给Spring去管理。每次数据库操作后，会关闭<code>Session</code>，当我们想要用懒加载方式去获得数据的时候，原来的<code>Session</code>已经关闭，不能获取数据，所以会抛出这样的异常。</p><p>解决方法： 在<code>application.yml</code>中做如下配置：</p><div class="language-yaml ext-yml line-numbers-mode"><pre class="language-yaml"><code><span class="token key atrule">spring</span><span class="token punctuation">:</span>
  <span class="token key atrule">jpa</span><span class="token punctuation">:</span>
    <span class="token key atrule">open-in-view</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
    <span class="token key atrule">properties</span><span class="token punctuation">:</span>
      <span class="token key atrule">hibernate</span><span class="token punctuation">:</span>
        <span class="token key atrule">enable_lazy_load_no_trans</span><span class="token punctuation">:</span> <span class="token boolean important">true</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h4 id="一对多-多对一" tabindex="-1"><a class="header-anchor" href="#一对多-多对一" aria-hidden="true">#</a> 一对多（多对一）</h4><p><code>/src/main/java/com/example/springbootjpa/entity/Department</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Data</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>annotations<span class="token punctuation">.</span></span><span class="token class-name">GenericGenerator</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Set</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Entity</span>
<span class="token annotation punctuation">@Table</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;tb_dept&quot;</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Department</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Id</span>
    <span class="token annotation punctuation">@GenericGenerator</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">,</span> strategy <span class="token operator">=</span> <span class="token string">&quot;uuid&quot;</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@GeneratedValue</span><span class="token punctuation">(</span>generator <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> id<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;dept_name&quot;</span><span class="token punctuation">,</span> unique <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> deptName<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@OneToMany</span><span class="token punctuation">(</span>mappedBy <span class="token operator">=</span> <span class="token string">&quot;department&quot;</span><span class="token punctuation">,</span> cascade <span class="token operator">=</span> <span class="token class-name">CascadeType</span><span class="token punctuation">.</span>ALL<span class="token punctuation">,</span> fetch <span class="token operator">=</span> <span class="token class-name">FetchType</span><span class="token punctuation">.</span>LAZY<span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Employee</span><span class="token punctuation">&gt;</span></span> employees<span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br></div></div><p><code>/src/main/java/com/example/springbootjpa/entity/Employee</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Data</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>annotations<span class="token punctuation">.</span></span><span class="token class-name">GenericGenerator</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span>UUID<span class="token punctuation">;</span>

<span class="token annotation punctuation">@Entity</span>
<span class="token annotation punctuation">@Table</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;tb_emp&quot;</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Employee</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Id</span>
    <span class="token annotation punctuation">@GenericGenerator</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">,</span> strategy <span class="token operator">=</span> <span class="token string">&quot;uuid&quot;</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@GeneratedValue</span><span class="token punctuation">(</span>generator <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> id<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;emp_name&quot;</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> empName<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;emp_job&quot;</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> empJob<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;dept_id&quot;</span><span class="token punctuation">,</span> insertable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> updatable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> deptId<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@ManyToOne</span><span class="token punctuation">(</span>targetEntity <span class="token operator">=</span> <span class="token class-name">Department</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> cascade <span class="token operator">=</span> <span class="token class-name">CascadeType</span><span class="token punctuation">.</span>ALL<span class="token punctuation">,</span> fetch <span class="token operator">=</span> <span class="token class-name">FetchType</span><span class="token punctuation">.</span>LAZY<span class="token punctuation">)</span>
    <span class="token annotation punctuation">@JoinColumn</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;dept_id&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">Department</span> department<span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br></div></div><p>测试</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">findByIdTest</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Optional</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Employee</span><span class="token punctuation">&gt;</span></span> optional <span class="token operator">=</span> employeeRepository<span class="token punctuation">.</span><span class="token function">findById</span><span class="token punctuation">(</span><span class="token string">&quot;93fce66c1ef340fa866d5bd389de3d79&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>optional<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>结果报错了...</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>StackOverflowError</span>
    at java<span class="token punctuation">.</span>base<span class="token operator">/</span><span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>Exception</span><span class="token punctuation">.</span><span class="token generics"><span class="token punctuation">&lt;</span>init<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token class-name">Exception</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">102</span><span class="token punctuation">)</span>
    at java<span class="token punctuation">.</span>base<span class="token operator">/</span><span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>ReflectiveOperationException</span><span class="token punctuation">.</span><span class="token generics"><span class="token punctuation">&lt;</span>init<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token class-name">ReflectiveOperationException</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">89</span><span class="token punctuation">)</span>
    at java<span class="token punctuation">.</span>base<span class="token operator">/</span><span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span>InvocationTargetException</span><span class="token punctuation">.</span><span class="token generics"><span class="token punctuation">&lt;</span>init<span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token class-name">InvocationTargetException</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">73</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">jdk<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span>GeneratedConstructorAccessor54</span><span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token class-name">Unknown</span> <span class="token class-name">Source</span><span class="token punctuation">)</span>
    at java<span class="token punctuation">.</span>base<span class="token operator">/</span><span class="token class-name"><span class="token namespace">jdk<span class="token punctuation">.</span>internal<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span>DelegatingConstructorAccessorImpl</span><span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token class-name">DelegatingConstructorAccessorImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">45</span><span class="token punctuation">)</span>
    at java<span class="token punctuation">.</span>base<span class="token operator">/</span><span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span>reflect<span class="token punctuation">.</span></span>Constructor</span><span class="token punctuation">.</span><span class="token function">newInstance</span><span class="token punctuation">(</span><span class="token class-name">Constructor</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">488</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>Util</span><span class="token punctuation">.</span><span class="token function">handleNewInstance</span><span class="token punctuation">(</span><span class="token class-name">Util</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">425</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>PreparedStatement</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token class-name">PreparedStatement</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">761</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>ConnectionImpl</span><span class="token punctuation">.</span><span class="token function">clientPrepareStatement</span><span class="token punctuation">(</span><span class="token class-name">ConnectionImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1404</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>ConnectionImpl</span><span class="token punctuation">.</span><span class="token function">prepareStatement</span><span class="token punctuation">(</span><span class="token class-name">ConnectionImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">4121</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>ConnectionImpl</span><span class="token punctuation">.</span><span class="token function">prepareStatement</span><span class="token punctuation">(</span><span class="token class-name">ConnectionImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">4025</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>zaxxer<span class="token punctuation">.</span>hikari<span class="token punctuation">.</span>pool<span class="token punctuation">.</span></span>ProxyConnection</span><span class="token punctuation">.</span><span class="token function">prepareStatement</span><span class="token punctuation">(</span><span class="token class-name">ProxyConnection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">318</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>zaxxer<span class="token punctuation">.</span>hikari<span class="token punctuation">.</span>pool<span class="token punctuation">.</span></span>HikariProxyConnection</span><span class="token punctuation">.</span><span class="token function">prepareStatement</span><span class="token punctuation">(</span><span class="token class-name">HikariProxyConnection</span><span class="token punctuation">.</span>java<span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>engine<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>StatementPreparerImpl</span>$<span class="token number">5.</span><span class="token function">doPrepare</span><span class="token punctuation">(</span><span class="token class-name">StatementPreparerImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">145</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>engine<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>StatementPreparerImpl</span>$<span class="token class-name">StatementPreparationTemplate</span><span class="token punctuation">.</span><span class="token function">prepareStatement</span><span class="token punctuation">(</span><span class="token class-name">StatementPreparerImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">171</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>engine<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>StatementPreparerImpl</span><span class="token punctuation">.</span><span class="token function">prepareQueryStatement</span><span class="token punctuation">(</span><span class="token class-name">StatementPreparerImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">147</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>plan<span class="token punctuation">.</span>exec<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span><span class="token function">prepareQueryStatement</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">226</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>plan<span class="token punctuation">.</span>exec<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span><span class="token function">executeQueryStatement</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">190</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>plan<span class="token punctuation">.</span>exec<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span><span class="token function">executeLoad</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">121</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>plan<span class="token punctuation">.</span>exec<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span><span class="token function">executeLoad</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">86</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>plan<span class="token punctuation">.</span></span>AbstractLoadPlanBasedCollectionInitializer</span><span class="token punctuation">.</span><span class="token function">initialize</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedCollectionInitializer</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">87</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>persister<span class="token punctuation">.</span>collection<span class="token punctuation">.</span></span>AbstractCollectionPersister</span><span class="token punctuation">.</span><span class="token function">initialize</span><span class="token punctuation">(</span><span class="token class-name">AbstractCollectionPersister</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">688</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>event<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>DefaultInitializeCollectionEventListener</span><span class="token punctuation">.</span><span class="token function">onInitializeCollection</span><span class="token punctuation">(</span><span class="token class-name">DefaultInitializeCollectionEventListener</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">75</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>SessionImpl</span><span class="token punctuation">.</span><span class="token function">initializeCollection</span><span class="token punctuation">(</span><span class="token class-name">SessionImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">2223</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractPersistentCollection</span>$<span class="token number">4.</span><span class="token function">doWork</span><span class="token punctuation">(</span><span class="token class-name">AbstractPersistentCollection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">565</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractPersistentCollection</span><span class="token punctuation">.</span><span class="token function">withTemporarySessionIfNeeded</span><span class="token punctuation">(</span><span class="token class-name">AbstractPersistentCollection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">247</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractPersistentCollection</span><span class="token punctuation">.</span><span class="token function">initialize</span><span class="token punctuation">(</span><span class="token class-name">AbstractPersistentCollection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">561</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractPersistentCollection</span><span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token class-name">AbstractPersistentCollection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">132</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>PersistentSet</span><span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token class-name">PersistentSet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">430</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity<span class="token punctuation">.</span></span>Department</span><span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token class-name">Department</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">14</span><span class="token punctuation">)</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br></div></div><p>通过日志看sql的输出，发现了sql重复执行了好多次。以下我截取了前10条sql记录。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">Hibernate</span><span class="token operator">:</span> select employee0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employee0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employee0_<span class="token punctuation">.</span>emp_job as emp_job3_1_0_<span class="token punctuation">,</span> employee0_<span class="token punctuation">.</span>emp_name as emp_name4_1_0_ from tb_emp employee0_ where employee0_<span class="token punctuation">.</span>id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select department0_<span class="token punctuation">.</span>id as id1_0_0_<span class="token punctuation">,</span> department0_<span class="token punctuation">.</span>dept_name as dept_nam2_0_0_ from tb_dept department0_ where department0_<span class="token punctuation">.</span>id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_job as emp_job3_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_name as emp_name4_1_1_ from tb_emp employees0_ where employees0_<span class="token punctuation">.</span>dept_id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select department0_<span class="token punctuation">.</span>id as id1_0_0_<span class="token punctuation">,</span> department0_<span class="token punctuation">.</span>dept_name as dept_nam2_0_0_ from tb_dept department0_ where department0_<span class="token punctuation">.</span>id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_job as emp_job3_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_name as emp_name4_1_1_ from tb_emp employees0_ where employees0_<span class="token punctuation">.</span>dept_id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_job as emp_job3_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_name as emp_name4_1_1_ from tb_emp employees0_ where employees0_<span class="token punctuation">.</span>dept_id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_job as emp_job3_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_name as emp_name4_1_1_ from tb_emp employees0_ where employees0_<span class="token punctuation">.</span>dept_id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_job as emp_job3_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_name as emp_name4_1_1_ from tb_emp employees0_ where employees0_<span class="token punctuation">.</span>dept_id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_job as emp_job3_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_name as emp_name4_1_1_ from tb_emp employees0_ where employees0_<span class="token punctuation">.</span>dept_id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>id as id1_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>dept_id as dept_id2_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_job as emp_job3_1_1_<span class="token punctuation">,</span> employees0_<span class="token punctuation">.</span>emp_name as emp_name4_1_1_ from tb_emp employees0_ where employees0_<span class="token punctuation">.</span>dept_id<span class="token operator">=</span><span class="token operator">?</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>通过观察发现，第一条sql是执行查询Employee的sql，第二条sql是执行查询Department的sql，第三条sql是执行Department里面所有员工的sql，第四条sql是执行查询Department的sql，后面所有的sql都是执行查询Department里面所有员工的sql。</p><p>很明显发生了循环依赖的情况。这是<code>Lombok</code>的<code>@Data</code>注解的锅。<code>Lombok</code>的<code>@Data</code>注解相当于<code>@Getter</code>、<code>@Setter</code>、<code>@RequiredArgsConstructor</code>、<code>@ToString</code>、<code>@EqualsAndHashCode</code>这几个注解。</p><p>我们可以通过反编译看一下<code>Lombok</code>生成的<code>toString()</code>方法</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// Employee</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token string">&quot;Employee(id=&quot;</span> <span class="token operator">+</span> <span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;, empName=&quot;</span> <span class="token operator">+</span> <span class="token function">getEmpName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;, empJob=&quot;</span> <span class="token operator">+</span> <span class="token function">getEmpJob</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;, deptId=&quot;</span> <span class="token operator">+</span> <span class="token function">getDeptId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;, department=&quot;</span> <span class="token operator">+</span> <span class="token function">getDepartment</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;)&quot;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Department</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
  <span class="token keyword">return</span> <span class="token string">&quot;Department(id=&quot;</span> <span class="token operator">+</span> <span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;, deptName=&quot;</span> <span class="token operator">+</span> <span class="token function">getDeptName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;, employees=&quot;</span> <span class="token operator">+</span> <span class="token function">getEmployees</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">&quot;)&quot;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>可以发现<code>Lombok</code>为我们生成的<code>toString()</code>方法覆盖了整个类的所有属性 现在将 <code>@Data</code> 注解去掉，替换为 <code>@Setter</code>、<code>@Getter</code>、<code>@EqualsAndHashCode</code>，重写 <code>toString()</code> 方法</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// Department</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string">&quot;Department{&quot;</span> <span class="token operator">+</span>
            <span class="token string">&quot;id=&#39;&quot;</span> <span class="token operator">+</span> id <span class="token operator">+</span> <span class="token string">&#39;\&#39;&#39;</span> <span class="token operator">+</span>
            <span class="token string">&quot;, deptName=&#39;&quot;</span> <span class="token operator">+</span> deptName <span class="token operator">+</span> <span class="token string">&#39;\&#39;&#39;</span> <span class="token operator">+</span>
            <span class="token string">&#39;}&#39;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Employee</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token string">&quot;Employee{&quot;</span> <span class="token operator">+</span>
            <span class="token string">&quot;id=&#39;&quot;</span> <span class="token operator">+</span> id <span class="token operator">+</span> <span class="token string">&#39;\&#39;&#39;</span> <span class="token operator">+</span>
            <span class="token string">&quot;, empName=&#39;&quot;</span> <span class="token operator">+</span> empName <span class="token operator">+</span> <span class="token string">&#39;\&#39;&#39;</span> <span class="token operator">+</span>
            <span class="token string">&quot;, empJob=&#39;&quot;</span> <span class="token operator">+</span> empJob <span class="token operator">+</span> <span class="token string">&#39;\&#39;&#39;</span> <span class="token operator">+</span>
            <span class="token string">&quot;, deptId=&#39;&quot;</span> <span class="token operator">+</span> deptId <span class="token operator">+</span> <span class="token string">&#39;\&#39;&#39;</span> <span class="token operator">+</span>
            <span class="token string">&quot;, department=&quot;</span> <span class="token operator">+</span> department <span class="token operator">+</span>
            <span class="token string">&#39;}&#39;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><p>再次运行测试用例，测试通过，以上Employee toString()方法打印的department会触发懒加载，最终日志输出的sql如下：</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">Hibernate</span><span class="token operator">:</span> select employee0_<span class="token punctuation">.</span>id as id1_1_0_<span class="token punctuation">,</span> employee0_<span class="token punctuation">.</span>dept_id as dept_id2_1_0_<span class="token punctuation">,</span> employee0_<span class="token punctuation">.</span>emp_job as emp_job3_1_0_<span class="token punctuation">,</span> employee0_<span class="token punctuation">.</span>emp_name as emp_name4_1_0_ from tb_emp employee0_ where employee0_<span class="token punctuation">.</span>id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Hibernate</span><span class="token operator">:</span> select department0_<span class="token punctuation">.</span>id as id1_0_0_<span class="token punctuation">,</span> department0_<span class="token punctuation">.</span>dept_name as dept_nam2_0_0_ from tb_dept department0_ where department0_<span class="token punctuation">.</span>id<span class="token operator">=</span><span class="token operator">?</span>
<span class="token class-name">Employee</span><span class="token punctuation">{</span>id<span class="token operator">=</span><span class="token string">&#39;93fce66c1ef340fa866d5bd389de3d79&#39;</span><span class="token punctuation">,</span> empName<span class="token operator">=</span><span class="token string">&#39;jack&#39;</span><span class="token punctuation">,</span> empJob<span class="token operator">=</span><span class="token string">&#39;hr&#39;</span><span class="token punctuation">,</span> deptId<span class="token operator">=</span><span class="token string">&#39;0a4fe7234fff42afad34f6a06a8e1821&#39;</span><span class="token punctuation">,</span> department<span class="token operator">=</span><span class="token class-name">Department</span><span class="token punctuation">{</span>id<span class="token operator">=</span><span class="token string">&#39;0a4fe7234fff42afad34f6a06a8e1821&#39;</span><span class="token punctuation">,</span> deptName<span class="token operator">=</span><span class="token string">&#39;人事部&#39;</span><span class="token punctuation">}</span><span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>再来测试查询Department</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">findByIdTest</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">Optional</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Department</span><span class="token punctuation">&gt;</span></span> optional <span class="token operator">=</span> departmentRepository<span class="token punctuation">.</span><span class="token function">findById</span><span class="token punctuation">(</span><span class="token string">&quot;0a4fe7234fff42afad34f6a06a8e1821&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Employee</span><span class="token punctuation">&gt;</span></span> employees <span class="token operator">=</span> optional<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getEmployees</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Assert</span><span class="token punctuation">.</span><span class="token function">assertNotEquals</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> employees<span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>同样还是报了堆栈溢出，错误定位在Department和Employee的hashCode()方法上</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>lang<span class="token punctuation">.</span></span>StackOverflowError</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>Util</span><span class="token punctuation">.</span><span class="token function">handleNewInstance</span><span class="token punctuation">(</span><span class="token class-name">Util</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">439</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>ResultSetImpl</span><span class="token punctuation">.</span><span class="token function">getInstance</span><span class="token punctuation">(</span><span class="token class-name">ResultSetImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">342</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>MysqlIO</span><span class="token punctuation">.</span><span class="token function">buildResultSetWithRows</span><span class="token punctuation">(</span><span class="token class-name">MysqlIO</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">3132</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>MysqlIO</span><span class="token punctuation">.</span><span class="token function">getResultSet</span><span class="token punctuation">(</span><span class="token class-name">MysqlIO</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">477</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>MysqlIO</span><span class="token punctuation">.</span><span class="token function">readResultsForQueryOrUpdate</span><span class="token punctuation">(</span><span class="token class-name">MysqlIO</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">3115</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>MysqlIO</span><span class="token punctuation">.</span><span class="token function">readAllResults</span><span class="token punctuation">(</span><span class="token class-name">MysqlIO</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">2344</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>MysqlIO</span><span class="token punctuation">.</span><span class="token function">sqlQueryDirect</span><span class="token punctuation">(</span><span class="token class-name">MysqlIO</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">2739</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>ConnectionImpl</span><span class="token punctuation">.</span><span class="token function">execSQL</span><span class="token punctuation">(</span><span class="token class-name">ConnectionImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">2486</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>PreparedStatement</span><span class="token punctuation">.</span><span class="token function">executeInternal</span><span class="token punctuation">(</span><span class="token class-name">PreparedStatement</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1858</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>mysql<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span></span>PreparedStatement</span><span class="token punctuation">.</span><span class="token function">executeQuery</span><span class="token punctuation">(</span><span class="token class-name">PreparedStatement</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">1966</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>zaxxer<span class="token punctuation">.</span>hikari<span class="token punctuation">.</span>pool<span class="token punctuation">.</span></span>ProxyPreparedStatement</span><span class="token punctuation">.</span><span class="token function">executeQuery</span><span class="token punctuation">(</span><span class="token class-name">ProxyPreparedStatement</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">52</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>zaxxer<span class="token punctuation">.</span>hikari<span class="token punctuation">.</span>pool<span class="token punctuation">.</span></span>HikariProxyPreparedStatement</span><span class="token punctuation">.</span><span class="token function">executeQuery</span><span class="token punctuation">(</span><span class="token class-name">HikariProxyPreparedStatement</span><span class="token punctuation">.</span>java<span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>engine<span class="token punctuation">.</span>jdbc<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>ResultSetReturnImpl</span><span class="token punctuation">.</span><span class="token function">extract</span><span class="token punctuation">(</span><span class="token class-name">ResultSetReturnImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">60</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>plan<span class="token punctuation">.</span>exec<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span><span class="token function">getResultSet</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">419</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>plan<span class="token punctuation">.</span>exec<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span><span class="token function">executeQueryStatement</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">191</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>plan<span class="token punctuation">.</span>exec<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span><span class="token function">executeLoad</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">121</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>plan<span class="token punctuation">.</span>exec<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span><span class="token function">executeLoad</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedLoader</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">86</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>loader<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>plan<span class="token punctuation">.</span></span>AbstractLoadPlanBasedCollectionInitializer</span><span class="token punctuation">.</span><span class="token function">initialize</span><span class="token punctuation">(</span><span class="token class-name">AbstractLoadPlanBasedCollectionInitializer</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">87</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>persister<span class="token punctuation">.</span>collection<span class="token punctuation">.</span></span>AbstractCollectionPersister</span><span class="token punctuation">.</span><span class="token function">initialize</span><span class="token punctuation">(</span><span class="token class-name">AbstractCollectionPersister</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">688</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>event<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>DefaultInitializeCollectionEventListener</span><span class="token punctuation">.</span><span class="token function">onInitializeCollection</span><span class="token punctuation">(</span><span class="token class-name">DefaultInitializeCollectionEventListener</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">75</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>SessionImpl</span><span class="token punctuation">.</span><span class="token function">initializeCollection</span><span class="token punctuation">(</span><span class="token class-name">SessionImpl</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">2223</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractPersistentCollection</span>$<span class="token number">4.</span><span class="token function">doWork</span><span class="token punctuation">(</span><span class="token class-name">AbstractPersistentCollection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">565</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractPersistentCollection</span><span class="token punctuation">.</span><span class="token function">withTemporarySessionIfNeeded</span><span class="token punctuation">(</span><span class="token class-name">AbstractPersistentCollection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">247</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractPersistentCollection</span><span class="token punctuation">.</span><span class="token function">initialize</span><span class="token punctuation">(</span><span class="token class-name">AbstractPersistentCollection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">561</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>AbstractPersistentCollection</span><span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token class-name">AbstractPersistentCollection</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">132</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>collection<span class="token punctuation">.</span>internal<span class="token punctuation">.</span></span>PersistentSet</span><span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token class-name">PersistentSet</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">430</span><span class="token punctuation">)</span>
    at <span class="token class-name"><span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity<span class="token punctuation">.</span></span>Department</span><span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token class-name">Department</span><span class="token punctuation">.</span>java<span class="token operator">:</span><span class="token number">17</span><span class="token punctuation">)</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br></div></div><p>依旧是<code>Lombok</code>的锅，<code>@EqualsAndHashCode</code>为我们生成的<code>equals()</code>和<code>hashCode()</code>方法会使用所有属性，注意，<code>Department</code>中<code>employees</code>是<code>Se</code>t集合，当我们调用<code>department.getEmployees()</code>时，<code>Employee</code>的<code>hashCode()</code>方法会被调用，<code>Employee</code>中的<code>hashCode()</code>又依赖于<code>Department</code>的<code>HashCode()</code>方法，这样又形成了循环引用...</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// Department</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">43</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> $id <span class="token operator">=</span> <span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> result <span class="token operator">=</span> <span class="token punctuation">(</span>$id <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token number">43</span> <span class="token operator">:</span> $id<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">59</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> $deptName <span class="token operator">=</span> <span class="token function">getDeptName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    result <span class="token operator">=</span> <span class="token punctuation">(</span>result <span class="token operator">*</span> <span class="token number">59</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span>$deptName <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token number">43</span> <span class="token operator">:</span> $deptName<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Set</span> $employees <span class="token operator">=</span> <span class="token function">getEmployees</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> i2 <span class="token operator">=</span> result <span class="token operator">*</span> <span class="token number">59</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>$employees <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        i <span class="token operator">=</span> $employees<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> i2 <span class="token operator">+</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Employee</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">43</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> $id <span class="token operator">=</span> <span class="token function">getId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> result <span class="token operator">=</span> <span class="token punctuation">(</span>$id <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token number">43</span> <span class="token operator">:</span> $id<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token number">59</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> $empName <span class="token operator">=</span> <span class="token function">getEmpName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    result <span class="token operator">=</span> <span class="token punctuation">(</span>result <span class="token operator">*</span> <span class="token number">59</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span>$empName <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token number">43</span> <span class="token operator">:</span> $empName<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> $empJob <span class="token operator">=</span> <span class="token function">getEmpJob</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    result <span class="token operator">=</span> <span class="token punctuation">(</span>result <span class="token operator">*</span> <span class="token number">59</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span>$empJob <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token number">43</span> <span class="token operator">:</span> $empJob<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> $deptId <span class="token operator">=</span> <span class="token function">getDeptId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    result <span class="token operator">=</span> <span class="token punctuation">(</span>result <span class="token operator">*</span> <span class="token number">59</span><span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token punctuation">(</span>$deptId <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token number">43</span> <span class="token operator">:</span> $deptId<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">Department</span> $department <span class="token operator">=</span> <span class="token function">getDepartment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> i2 <span class="token operator">=</span> result <span class="token operator">*</span> <span class="token number">59</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>$department <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        i <span class="token operator">=</span> $department<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> i2 <span class="token operator">+</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br></div></div><p>自己动手重写 <code>equals()</code> 和 <code>hashCode()</code> 方法，去掉 <code>@EqualsAndHashCode</code> 注解</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// Department</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">equals</span><span class="token punctuation">(</span><span class="token class-name">Object</span> o<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token operator">==</span> o<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>o <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> o<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token class-name">Department</span> that <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Department</span><span class="token punctuation">)</span> o<span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> that<span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
            <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>deptName<span class="token punctuation">,</span> that<span class="token punctuation">.</span>deptName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">hash</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> deptName<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// Employee</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">boolean</span> <span class="token function">equals</span><span class="token punctuation">(</span><span class="token class-name">Object</span> o<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token operator">==</span> o<span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">true</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>o <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">||</span> <span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">!=</span> o<span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token boolean">false</span><span class="token punctuation">;</span>
    <span class="token class-name">Employee</span> employee <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Employee</span><span class="token punctuation">)</span> o<span class="token punctuation">;</span>
    <span class="token keyword">return</span> <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> employee<span class="token punctuation">.</span>id<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
            <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>empName<span class="token punctuation">,</span> employee<span class="token punctuation">.</span>empName<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
            <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>empJob<span class="token punctuation">,</span> employee<span class="token punctuation">.</span>empJob<span class="token punctuation">)</span> <span class="token operator">&amp;&amp;</span>
            <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span>deptId<span class="token punctuation">,</span> employee<span class="token punctuation">.</span>deptId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token class-name">Objects</span><span class="token punctuation">.</span><span class="token function">hash</span><span class="token punctuation">(</span>id<span class="token punctuation">,</span> empName<span class="token punctuation">,</span> empJob<span class="token punctuation">,</span> deptId<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br></div></div><p>再次运行测试用例，测试通过</p><blockquote><p>总结：慎用 <code>@Data</code> 注解，使用 <code>@Getter</code>、<code>@Setter</code>注解，需要时自己重写 <code>toString()</code>、<code>equals()</code>以及 <code>hashCode()</code>方法</p></blockquote><h2 id="审计auditing" tabindex="-1"><a class="header-anchor" href="#审计auditing" aria-hidden="true">#</a> 审计Auditing</h2><p>参考自<a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#auditing" target="_blank" rel="noopener noreferrer">官方文档5.9Auditing<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a></p><p>一般数据库表在设计时都会添加4个审计字段，<code>Spring Data Jpa</code> 同样支持审计功能。<code>Spring Data</code> 提供了<code>@CreatedBy</code>，<code>@LastModifiedBy</code>，<code>@CreatedDate</code>，<code>@LastModifiedDate</code> 4个注解来记录表中记录的创建及修改信息。</p><p><strong>实体类</strong></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>entity</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Data</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>hibernate<span class="token punctuation">.</span>annotations<span class="token punctuation">.</span></span><span class="token class-name">GenericGenerator</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">CreatedBy</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">CreatedDate</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">LastModifiedBy</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>annotation<span class="token punctuation">.</span></span><span class="token class-name">LastModifiedDate</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span>domain<span class="token punctuation">.</span>support<span class="token punctuation">.</span></span><span class="token class-name">AuditingEntityListener</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">javax<span class="token punctuation">.</span>persistence<span class="token punctuation">.</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Date</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Set</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Entity</span>
<span class="token annotation punctuation">@EntityListeners</span><span class="token punctuation">(</span><span class="token class-name">AuditingEntityListener</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Table</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;tb_user&quot;</span><span class="token punctuation">)</span>
<span class="token annotation punctuation">@Data</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">User</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Id</span>
    <span class="token annotation punctuation">@GenericGenerator</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">,</span> strategy <span class="token operator">=</span> <span class="token string">&quot;uuid&quot;</span><span class="token punctuation">)</span>
    <span class="token annotation punctuation">@GeneratedValue</span><span class="token punctuation">(</span>generator <span class="token operator">=</span> <span class="token string">&quot;idGenerator&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> id<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;username&quot;</span><span class="token punctuation">,</span> unique <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> username<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;password&quot;</span><span class="token punctuation">,</span> nullable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> password<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;email&quot;</span><span class="token punctuation">,</span> unique <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> email<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@ManyToMany</span><span class="token punctuation">(</span>targetEntity <span class="token operator">=</span> <span class="token class-name">Role</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> cascade <span class="token operator">=</span> <span class="token class-name">CascadeType</span><span class="token punctuation">.</span>ALL<span class="token punctuation">,</span> fetch <span class="token operator">=</span> <span class="token class-name">FetchType</span><span class="token punctuation">.</span>LAZY<span class="token punctuation">)</span>
    <span class="token annotation punctuation">@JoinTable</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;tb_user_role&quot;</span><span class="token punctuation">,</span> joinColumns <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token annotation punctuation">@JoinColumn</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;user_id&quot;</span><span class="token punctuation">,</span> referencedColumnName <span class="token operator">=</span> <span class="token string">&quot;id&quot;</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
            inverseJoinColumns <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token annotation punctuation">@JoinColumn</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;role_id&quot;</span><span class="token punctuation">,</span> referencedColumnName <span class="token operator">=</span> <span class="token string">&quot;id&quot;</span><span class="token punctuation">)</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Role</span><span class="token punctuation">&gt;</span></span> roles<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@CreatedDate</span>
    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;created_date&quot;</span><span class="token punctuation">,</span> updatable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">Date</span> createdDate<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@CreatedBy</span>
    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;created_by&quot;</span><span class="token punctuation">,</span> updatable <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> createdBy<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@LastModifiedDate</span>
    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;updated_date&quot;</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">Date</span> updatedDate<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@LastModifiedBy</span>
    <span class="token annotation punctuation">@Column</span><span class="token punctuation">(</span>name <span class="token operator">=</span> <span class="token string">&quot;updated_by&quot;</span><span class="token punctuation">,</span> length <span class="token operator">=</span> <span class="token number">64</span><span class="token punctuation">)</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> updatedBy<span class="token punctuation">;</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br></div></div><p>实体类上还添加了 <code>@EntityListeners(AuditingEntityListener.class)</code>，而 <code>AuditingEntityListener</code> 是由 <code>Spring Data Jpa</code> 提供的</p><h3 id="实现auditoraware接口" tabindex="-1"><a class="header-anchor" href="#实现auditoraware接口" aria-hidden="true">#</a> 实现AuditorAware接口</h3><p>光添加了4个审计注解还不够，得告诉程序到底是谁在创建和修改表记录</p><p><code>/src/main/java/com/example/springbootjpa/auditing/AuditorAwareImpl</code></p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa<span class="token punctuation">.</span>auditing</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>domain<span class="token punctuation">.</span></span><span class="token class-name">AuditorAware</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>stereotype<span class="token punctuation">.</span></span><span class="token class-name">Component</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span></span><span class="token class-name">Optional</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Component</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">AuditorAwareImpl</span> <span class="token keyword">implements</span> <span class="token class-name">AuditorAware</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token class-name">Optional</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> <span class="token function">getCurrentAuditor</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token class-name">Optional</span><span class="token punctuation">.</span><span class="token function">of</span><span class="token punctuation">(</span><span class="token string">&quot;admin&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><p>这里简单的返回了一个&quot;admin&quot;字符串来代表当前用户名</p><h3 id="启用jpa审计功能" tabindex="-1"><a class="header-anchor" href="#启用jpa审计功能" aria-hidden="true">#</a> 启用Jpa审计功能</h3><p>在<code>Spring Boot</code>启动类上添加 <code>@EnableJpaAuditing</code> 注解用于启用Jpa的审计功能</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>example<span class="token punctuation">.</span>springbootjpa</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span></span><span class="token class-name">SpringApplication</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>boot<span class="token punctuation">.</span>autoconfigure<span class="token punctuation">.</span></span><span class="token class-name">SpringBootApplication</span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token namespace">org<span class="token punctuation">.</span>springframework<span class="token punctuation">.</span>data<span class="token punctuation">.</span>jpa<span class="token punctuation">.</span>repository<span class="token punctuation">.</span>config<span class="token punctuation">.</span></span><span class="token class-name">EnableJpaAuditing</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@SpringBootApplication</span>
<span class="token annotation punctuation">@EnableJpaAuditing</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SpringBootJpaApplication</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">SpringApplication</span><span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token class-name">SpringBootJpaApplication</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>更多关于<a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#specifications" target="_blank" rel="noopener noreferrer">Jpa Specifications<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a>、<a href="https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#query-by-example" target="_blank" rel="noopener noreferrer">Example<span><svg class="icon outbound" xmlns="http://www.w3.org/2000/svg" ariahidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><!--[--><span class="sr-only">open in new window</span><!--]--></span></a>查询请查阅官方文档</p><!--]--></div><footer class="page-meta"><!----><div class="meta-item last-updated"><span class="meta-item-label">更新时间: </span><span class="meta-item-info">2021/9/8 上午12:03:33</span></div><div class="meta-item contributors"><span class="meta-item-label">贡献者: </span><span class="meta-item-info"><!--[--><!--[--><span class="contributor" title="email: pointer_v@qq.com">herodotus</span><!----><!--]--><!--]--></span></div></footer><nav class="page-nav"><p class="inner"><span class="prev"> ← <a href="/eurynome-cloud/basic-knowledge/" class="nav-link router-link-active" aria-label="介绍"><!--[--><!--]--> 介绍 <!--[--><!--]--></a></span><!----></p></nav><!--[--><!--]--></main><!--]--></div><!----><!--]--></div>
    <script src="/eurynome-cloud/assets/js/runtime~app.70302f05.js" defer></script><script src="/eurynome-cloud/assets/js/567.94e28fdc.js" defer></script><script src="/eurynome-cloud/assets/js/app.a36212f7.js" defer></script>
  </body>
</html>
